<script setup>
import { ref, onMounted, computed } from 'vue';
import { useRouter } from 'vue-router';
import { useRedisStore } from '@/stores/redis';
import { useUserStore } from '@/stores/user';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Check, Cpu, Monitor, Connection, InfoFilled, Setting, Coordinate, Refresh, Download, Upload, Delete, Close } from '@element-plus/icons-vue';
import UserAvatar from '@/components/UserAvatar.vue';

const router = useRouter();
const redisStore = useRedisStore();
const userStore = useUserStore();

// 标签页
const activeTab = ref('connection');

// 数据
const connected = ref(false);
const redisInfo = ref({});
const loading = ref(false);
const cacheKeys = ref([]);
const cacheValues = ref({});
const searchPattern = ref('');
const isProduction = ref(process.env.NODE_ENV === 'production');

// 分页相关变量
const currentPage = ref(1);
const pageSize = ref(50);
const totalKeys = ref(0);
const totalPages = ref(0);
const hasNextPage = ref(false);
const hasPrevPage = ref(false);

// 过滤类型
const selectedKeyType = ref('all');

// 数据库选择 - 从localStorage恢复或默认为DB0
const selectedDb = ref(parseInt(localStorage.getItem('redis_selected_db') || '0'));
const dbOptions = ref([
  { label: 'DB0 (默认)', value: 0 },
  { label: 'DB1', value: 1 },
  { label: 'DB2', value: 2 },
  { label: 'DB3', value: 3 },
  { label: 'DB4', value: 4 },
  { label: 'DB5', value: 5 }
]);

// 缓存操作表单
const cacheForm = ref({
  key: '',
  value: '',
  expire: 0,
  type: 'string', // 默认字符串类型
  // Hash类型专用字段
  hashField: '',
  hashValue: '',
  // ZSet类型专用字段
  zsetScore: 0,
  zsetMember: ''
});

// 数据类型选项
const dataTypeOptions = ref([
  { label: 'String (字符串)', value: 'string' },
  { label: 'List (列表)', value: 'list' },
  { label: 'Set (集合)', value: 'set' },
  { label: 'Hash (哈希)', value: 'hash' },
  { label: 'ZSet (有序集合)', value: 'zset' }
]);

// 导入对话框
const importDialogVisible = ref(false);
const importData = ref('');

// 数据库选择变化处理
const onDbChange = (dbIndex) => {
  selectedDb.value = dbIndex;
  // 持久化数据库选择
  localStorage.setItem('redis_selected_db', dbIndex.toString());
  
  // 如果已连接，重新加载数据
  if (connected.value) {
    loadCacheKeys(searchPattern.value || '*');
  }
};

// 测试Redis连接
const testConnection = async () => {
  loading.value = true;
  try {
    // 使用选定的数据库进行连接测试
    const result = await redisStore.testConnection(selectedDb.value);
    connected.value = redisStore.connected;
    if (connected.value) {
      ElMessage.success(`Redis连接成功 (DB${selectedDb.value})`);
      // 持久化连接状态和数据库选择
      localStorage.setItem('redis_connected', 'true');
      localStorage.setItem('redis_selected_db', selectedDb.value.toString());
      fetchRedisInfo();
    } else {
      ElMessage.error('Redis连接失败');
      localStorage.removeItem('redis_connected');
    }
  } catch (error) {
    console.error('Redis连接测试失败:', error);
    ElMessage.error('Redis连接测试失败: ' + (error.message || '未知错误'));
    localStorage.removeItem('redis_connected');
  } finally {
    loading.value = false;
  }
};

// 获取Redis信息
const fetchRedisInfo = async () => {
  loading.value = true;
  try {
    const info = await redisStore.fetchRedisInfo();
    redisInfo.value = info || {};
    connected.value = redisStore.connected;
    // 获取缓存键列表
    if (connected.value) {
      await loadCacheKeys();
    }
  } catch (error) {
    console.error('获取Redis信息失败:', error);
    ElMessage.error('获取Redis信息失败');
  } finally {
    loading.value = false;
  }
};

// 加载缓存键列表 - 支持模式搜索，避免自动全局扫描
const loadCacheKeys = async (pattern = '') => {
  // 生产环境禁止keys *全局扫描
  if (isProduction.value && (!pattern || pattern === '*')) {
    return;
  }
  
  if (!pattern || pattern.trim() === '') {
    return;
  }
  
  try {
    const result = await redisStore.getCacheKeys(pattern, selectedDb.value, currentPage.value, pageSize.value);
    if (result && result.keys) {
      cacheKeys.value = result.keys;
      totalKeys.value = result.total;
      totalPages.value = result.totalPages;
      hasNextPage.value = result.hasNext;
      hasPrevPage.value = result.hasPrev;
      
      // 限制只加载前10个键的值，避免性能问题
      if (result.keys && result.keys.length > 0) {
        await loadCacheValues(result.keys.slice(0, 10));
      }
    } else {
      cacheKeys.value = [];
    }
  } catch (error) {
    console.error('获取缓存键失败:', error);
    ElMessage.error('获取缓存键失败: ' + error.message);
  }
};

// 加载缓存值 - 避免自动请求复杂键名
const loadCacheValues = async (keys) => {
  for (const key of keys) {
    try {
      // 只处理简单字符串键名，避免JSON对象键名
      let keyStr;
      if (typeof key === 'object') {
        // 如果是对象，提取实际的key字段
        keyStr = key.key || JSON.stringify(key);
      } else {
        keyStr = String(key);
      }
      
      // 跳过过于复杂的键名，避免URL编码问题
      if (keyStr.includes('{') || keyStr.includes('%')) {
        console.log(`跳过复杂键名: ${keyStr}`);
        continue;
      }
      
      const value = await redisStore.getStringCache(keyStr, selectedDb.value);
      cacheValues.value[keyStr] = value;
    } catch (error) {
      console.error(`获取键 ${key} 的值失败:`, error);
    }
  }
};

// 存储每个键的数据类型
const keyTypes = ref({});

// 自动检测值的数据类型
const detectValueType = (value) => {
  if (value === null || value === undefined) return 'string';
  
  const strValue = String(value).trim();
  
  // 检查是否为ZSet格式（成员:分数）- 优先检查，因为包含特殊格式
  if (strValue.includes('(分数:') && strValue.includes(')')) {
    return 'zset';
  }
  
  // 检查是否为多行文本（List或Set）
  if (strValue.includes('\n')) {
    const lines = strValue.split('\n').filter(line => line.trim());
    if (lines.length > 1) {
      // 如果包含重复项，可能是List；如果都是唯一的，可能是Set
      const uniqueLines = [...new Set(lines)];
      return uniqueLines.length === lines.length ? 'set' : 'list';
    }
  }
  
  // 检查是否为键值对格式（Hash类型）
  if (strValue.includes(':') && !strValue.includes('\n') && !strValue.includes('(分数:')) {
    const parts = strValue.split(':');
    if (parts.length >= 2) {
      // 进一步验证是否真的是Hash格式（field: value）
      const trimmedParts = parts.map(p => p.trim());
      if (trimmedParts[0] && trimmedParts[1]) {
        return 'hash';
      }
    }
  }
  
  // 检查是否为JSON格式
  try {
    const parsed = JSON.parse(strValue);
    if (typeof parsed === 'object' && parsed !== null) {
      return Array.isArray(parsed) ? 'list' : 'hash';
    }
  } catch (e) {
    // 不是JSON格式，继续其他检查
  }
  
  return 'string';
};

// 判断值的类型 - 优先使用存储的类型信息
const getValueType = (key, value) => {
  // 如果有存储的类型信息，直接使用
  if (keyTypes.value[key]) {
    return keyTypes.value[key];
  }
  
  // 否则自动检测
  return detectValueType(value);
};

// 格式化显示值
const formatValue = (key, value) => {
  if (value === null || value === undefined) return 'null';
  
  const type = getValueType(key, value);
  switch (type) {
    case 'list':
    case 'set':
      // 多行显示，每行一个项目
      return value.split('\n').map(item => item.trim()).filter(item => item).join('\n');
    case 'hash':
      // 键值对格式显示
      return value;
    case 'zset':
      // 成员:分数格式显示
      return value;
    default:
      return value;
  }
};

// 过滤缓存键
const filteredCacheKeys = computed(() => {
  let keys = cacheKeys.value;
  
  // 按搜索关键字过滤
  if (searchPattern.value) {
    keys = keys.filter(key => 
      String(key).toLowerCase().includes(searchPattern.value.toLowerCase())
    );
  }
  
  // 按类型过滤
  if (selectedKeyType.value !== 'all') {
    keys = keys.filter(key => {
      const value = cacheValues.value[key];
      return getValueType(key, value) === selectedKeyType.value;
    });
  }
  
  return keys;
});

// 数据类型变化处理
const onTypeChange = (type) => {
  cacheForm.value.type = type;
  // 清空之前的值，为不同类型提供示例
  cacheForm.value.value = '';
  cacheForm.value.hashField = '';
  cacheForm.value.hashValue = '';
  cacheForm.value.zsetScore = 0;
  cacheForm.value.zsetMember = '';
  
  // 根据类型提供示例值
  switch (type) {
    case 'string':
      cacheForm.value.value = 'Hello Redis';
      break;
    case 'list':
      cacheForm.value.value = 'item1\nitem2\nitem3';
      break;
    case 'set':
      cacheForm.value.value = 'member1\nmember2\nmember3';
      break;
    case 'hash':
      cacheForm.value.hashField = 'field1';
      cacheForm.value.hashValue = 'value1';
      break;
    case 'zset':
      cacheForm.value.zsetMember = 'member1';
      cacheForm.value.zsetScore = 100;
      break;
  }
};

// 验证JSON格式
const isValidJson = (str) => {
  try {
    JSON.parse(str);
    return true;
  } catch {
    return false;
  }
};

// 设置缓存
const setCache = async () => {
  if (!cacheForm.value.key) {
    ElMessage.warning('请输入缓存键');
    return;
  }
  
  // 根据数据类型验证输入
  if (cacheForm.value.type === 'string' && !cacheForm.value.value) {
    ElMessage.warning('请输入字符串值');
    return;
  }
  if ((cacheForm.value.type === 'list' || cacheForm.value.type === 'set') && !cacheForm.value.value) {
    ElMessage.warning('请输入数据内容');
    return;
  }
  if (cacheForm.value.type === 'hash' && (!cacheForm.value.hashField || !cacheForm.value.hashValue)) {
    ElMessage.warning('请输入字段名和字段值');
    return;
  }
  if (cacheForm.value.type === 'zset' && !cacheForm.value.zsetMember) {
    ElMessage.warning('请输入成员名称');
    return;
  }
  
  loading.value = true;
  try {
    // 确保key是字符串类型
    const keyStr = typeof cacheForm.value.key === 'object' ? 
      JSON.stringify(cacheForm.value.key) : String(cacheForm.value.key);
    
    let success = false;
    try {
      switch (cacheForm.value.type) {
        case 'string':
          success = await redisStore.setStringCache(keyStr, cacheForm.value.value, selectedDb.value);
          break;
        case 'list':
          success = await redisStore.setListCache(keyStr, cacheForm.value.value.split('\n').filter(item => item.trim()), selectedDb.value);
          break;
        case 'set':
          success = await redisStore.setSetCache(keyStr, cacheForm.value.value.split('\n').filter(item => item.trim()), selectedDb.value);
          break;
        case 'hash':
          success = await redisStore.setHashCache(keyStr, cacheForm.value.hashField, cacheForm.value.hashValue, selectedDb.value);
          break;
        case 'zset':
          success = await redisStore.setZSetCache(keyStr, cacheForm.value.zsetMember, cacheForm.value.zsetScore, selectedDb.value);
          break;
        default:
          success = await redisStore.setStringCache(keyStr, cacheForm.value.value, selectedDb.value);
      }
    } catch (error) {
      console.error('设置缓存异常:', error);
      const errorMsg = error.message || error.toString() || '未知错误';
      if (errorMsg.includes('网络')) {
        ElMessage.error('网络连接异常，请检查Redis服务状态');
      } else if (errorMsg.includes('超时')) {
        ElMessage.error('请求超时，请稍后重试');
      } else if (errorMsg.includes('连接')) {
        ElMessage.error('Redis连接失败，请检查服务配置');
      } else {
        ElMessage.error(`设置缓存失败: ${errorMsg}`);
      }
      return;
    }

    if (success) {
      ElMessage.success('设置缓存成功');
      // 更新缓存键列表和值
      if (!Array.isArray(cacheKeys.value)) {
        cacheKeys.value = [];
      }
      if (!cacheKeys.value.includes(keyStr)) {
        cacheKeys.value.push(keyStr);
      }
      let displayValue = cacheForm.value.value;
      if (cacheForm.value.type === 'hash') {
        displayValue = `${cacheForm.value.hashField}: ${cacheForm.value.hashValue}`;
      } else if (cacheForm.value.type === 'zset') {
        displayValue = `${cacheForm.value.zsetMember} (分数: ${cacheForm.value.zsetScore})`;
      }
      cacheValues.value[keyStr] = displayValue;
      // 保存数据类型信息
      keyTypes.value[keyStr] = cacheForm.value.type;
      
      // 清空表单
      cacheForm.value.key = '';
      cacheForm.value.value = '';
      cacheForm.value.hashField = '';
      cacheForm.value.hashValue = '';
      cacheForm.value.zsetMember = '';
      cacheForm.value.zsetScore = 0;
      cacheForm.value.expire = 0;
    } else {
      ElMessage.error(`设置${cacheForm.value.type.toUpperCase()}缓存失败，请检查Redis连接状态`);
    }
  } catch (error) {
    console.error('设置缓存异常:', error);
    const errorMsg = error.message || error.toString() || '未知错误';
    if (errorMsg.includes('not a function')) {
      ElMessage.error('数据类型操作暂不支持，请联系管理员');
    } else if (errorMsg.includes('网络')) {
      ElMessage.error('网络连接异常，请检查Redis服务状态');
    } else {
      ElMessage.error(`设置缓存失败: ${errorMsg}`);
    }
  } finally {
    loading.value = false;
  }
};

// 获取缓存
const getCache = async () => {
  if (!cacheForm.value.key) {
    ElMessage.warning('请输入要获取的键');
    return;
  }
  
  loading.value = true;
  try {
    // 确保key是字符串类型
    const keyStr = typeof cacheForm.value.key === 'object' ? 
      JSON.stringify(cacheForm.value.key) : String(cacheForm.value.key);
    
    const value = await redisStore.getStringCache(keyStr, selectedDb.value);
    if (value !== null && value !== undefined && value !== '') {
      ElMessage.success('获取缓存成功');
      cacheForm.value.value = value;
      // 更新缓存键列表和值
      if (!Array.isArray(cacheKeys.value)) {
        cacheKeys.value = [];
      }
      if (!cacheKeys.value.includes(keyStr)) {
        cacheKeys.value.push(keyStr);
      }
      cacheValues.value[keyStr] = value;
      
      // 同时检查Redis原生数据类型
      try {
        const redisType = await redisStore.getKeyType(keyStr, selectedDatabase.value);
        console.log(`键 ${keyStr} 的Redis原生类型:`, redisType);
        
        // Redis类型映射到前端显示类型
        const typeMapping = {
          'string': 'string',
          'list': 'list', 
          'set': 'set',
          'hash': 'hash',
          'zset': 'zset',
          'none': 'string' // 键不存在时返回none
        };
        
        const mappedType = typeMapping[redisType] || 'string';
        keyTypes.value[keyStr] = mappedType;
        
        // 在控制台显示类型检查结果
        ElMessage.info(`键类型检查: ${keyStr} -> ${redisType.toUpperCase()}`);
      } catch (error) {
        console.warn('Redis类型检查失败，使用内容检测:', error);
        // 如果Redis TYPE命令失败，回退到内容检测
        const detectedType = detectValueType(value);
        keyTypes.value[keyStr] = detectedType;
      }
    } else {
      ElMessage.warning(`缓存键 "${keyStr}" 不存在或已过期`);
    }
  } catch (error) {
    console.error('获取缓存异常:', error);
    const errorMsg = error.message || error.toString() || '未知错误';
    if (errorMsg.includes('网络')) {
      ElMessage.error('🌐 网络连接异常，请检查Redis服务状态');
    } else if (errorMsg.includes('超时')) {
      ElMessage.error('⏰ 请求超时，请稍后重试或检查网络连接');
    } else if (errorMsg.includes('连接')) {
      ElMessage.error('🔌 Redis连接失败，请检查服务配置和端口');
    } else if (errorMsg.includes('404')) {
      ElMessage.error('❌ 缓存键不存在或接口路径错误');
    } else if (errorMsg.includes('500')) {
      ElMessage.error('⚠️ 服务器内部错误，请联系管理员');
    } else if (errorMsg.includes('403')) {
      ElMessage.error('🚫 权限不足，请检查Redis访问权限');
    } else {
      ElMessage.error(`💥 获取缓存失败: ${errorMsg}`);
    }
  } finally {
    loading.value = false;
  }
};

// 删除缓存
const deleteCache = async () => {
  if (!cacheForm.value.key) {
    ElMessage.warning('请输入要删除的键');
    return;
  }
  
  loading.value = true;
  try {
    // 确保key是字符串类型
    const keyStr = typeof cacheForm.value.key === 'object' ? 
      JSON.stringify(cacheForm.value.key) : String(cacheForm.value.key);
    
    const result = await redisStore.removeCacheValue(keyStr, selectedDb.value);
    if (result) {
      ElMessage.success('删除缓存成功');
      // 更新缓存键列表和值
      if (Array.isArray(cacheKeys.value)) {
        cacheKeys.value = cacheKeys.value.filter(key => key !== keyStr);
      } else {
        cacheKeys.value = [];
      }
      delete cacheValues.value[keyStr];
      // 清空表单
      cacheForm.value.value = '';
    } else {
      ElMessage.warning('未找到对应的缓存键');
    }
  } catch (error) {
    console.error('删除缓存失败:', error);
    ElMessage.error('删除缓存失败: ' + (error.message || '未知错误'));
  } finally {
    loading.value = false;
  }
};

// 选择缓存键
const selectCacheKey = (key) => {
  // 确保key是字符串类型
  const keyStr = typeof key === 'object' ? JSON.stringify(key) : String(key);
  cacheForm.value.key = keyStr;
  
  // 如果没有加载过这个键的值，则加载它
  if (cacheValues.value[keyStr] === undefined) {
    loadCacheValues([keyStr]);
  } else {
    cacheForm.value.value = cacheValues.value[keyStr];
  }
};

// 直接获取缓存（用于键列表中的查看按钮）
const getCacheByKey = async (key) => {
  loading.value = true;
  try {
    // 确保key是字符串类型
    const keyStr = typeof key === 'object' ? JSON.stringify(key) : String(key);
    
    const value = await redisStore.getStringCache(keyStr, selectedDb.value);
    if (value !== null && value !== undefined) {
      cacheValues.value[keyStr] = value;
      cacheForm.value.key = keyStr;
      cacheForm.value.value = value;
      ElMessage.success('获取缓存成功');
    } else {
      ElMessage.warning('未找到对应的缓存值');
    }
  } catch (error) {
    console.error('获取缓存失败:', error);
    ElMessage.error('获取缓存失败: ' + (error.message || '未知错误'));
  } finally {
    loading.value = false;
  }
};

// 直接删除缓存（用于键列表中的删除按钮）
const deleteCacheByKey = async (key) => {
  loading.value = true;
  try {
    // 确保key是字符串类型
    const keyStr = typeof key === 'object' ? JSON.stringify(key) : String(key);
    
    const result = await redisStore.removeCacheValue(keyStr, selectedDb.value);
    if (result) {
      ElMessage.success('删除缓存成功');
      if (Array.isArray(cacheKeys.value)) {
        cacheKeys.value = cacheKeys.value.filter(k => k !== keyStr);
      } else {
        cacheKeys.value = [];
      }
      delete cacheValues.value[keyStr];
    } else {
      ElMessage.warning('未找到对应的缓存键');
    }
  } catch (error) {
    console.error('删除缓存失败:', error);
    ElMessage.error('删除缓存失败: ' + (error.message || '未知错误'));
  } finally {
    loading.value = false;
  }
};

// 智能导出缓存 - 自动选择最优方案
const exportCacheOptimized = async () => {
  loading.value = true;
  try {
    const { exportCacheOptimized: exportAPI } = await import('@/api/redis');
    const response = await exportAPI(searchPattern.value || '*', selectedDb.value, 'auto');
    
    if (response.success) {
      if (response.exportMethod === 'json') {
        // JSON格式直接下载
        const dataStr = JSON.stringify(response.data, null, 2);
        const dataBlob = new Blob([dataStr], { type: 'application/json' });
        const url = URL.createObjectURL(dataBlob);
        const link = document.createElement('a');
        link.href = url;
        link.download = `redis-export-db${selectedDb.value}-${Date.now()}.json`;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
        ElMessage.success(response.message);
      } else if (response.exportMethod === 'batch') {
        // 分批导出提示
        ElMessageBox.confirm(
          `检测到大数据量(${response.exportInfo.totalKeys}键)，建议分批导出。是否继续？`,
          '大数据量导出',
          {
            confirmButtonText: '分批导出',
            cancelButtonText: '取消',
            type: 'warning'
          }
        ).then(() => {
          showBatchExportDialog(response.exportInfo);
        });
      }
    } else {
      ElMessage.error(response.message);
    }
  } catch (error) {
    console.error('智能导出失败:', error);
    ElMessage.error('导出失败: ' + (error.message || '未知错误'));
  } finally {
    loading.value = false;
  }
};

// 流式导出缓存 - 直接下载文件
const exportCacheStream = async () => {
  try {
    const { downloadCacheStream } = await import('@/api/redis');
    downloadCacheStream(searchPattern.value || '*', selectedDb.value);
    ElMessage.success('开始下载，请稍候...');
  } catch (error) {
    console.error('流式导出失败:', error);
    ElMessage.error('流式导出失败: ' + (error.message || '未知错误'));
  }
};

// 显示高级导出选项
const exportOptionsVisible = ref(false);
const exportOptions = ref({
  pattern: '*',
  method: 'auto',
  batchSize: 5000
});

const showExportOptions = () => {
  exportOptions.value.pattern = searchPattern.value || '*';
  exportOptionsVisible.value = true;
};

// 分批导出对话框
const batchExportVisible = ref(false);
const batchExportInfo = ref({});
const currentBatch = ref(1);
const batchExportProgress = ref(0);

const showBatchExportDialog = (exportInfo) => {
  batchExportInfo.value = exportInfo;
  currentBatch.value = 1;
  batchExportProgress.value = 0;
  batchExportVisible.value = true;
};

// 执行分批导出
const executeBatchExport = async () => {
  const { exportCacheBatch } = await import('@/api/redis');
  const allData = {};
  
  try {
    for (let i = 1; i <= batchExportInfo.value.totalBatches; i++) {
      currentBatch.value = i;
      const response = await exportCacheBatch(i, searchPattern.value || '*', selectedDb.value);
      
      if (response.success) {
        Object.assign(allData, response.data);
        batchExportProgress.value = Math.round((i / batchExportInfo.value.totalBatches) * 100);
      } else {
        throw new Error(`批次${i}导出失败: ${response.message}`);
      }
      
      // 避免请求过快
      if (i < batchExportInfo.value.totalBatches) {
        await new Promise(resolve => setTimeout(resolve, 100));
      }
    }
    
    // 下载合并后的数据
    const dataStr = JSON.stringify(allData, null, 2);
    const dataBlob = new Blob([dataStr], { type: 'application/json' });
    const url = URL.createObjectURL(dataBlob);
    const link = document.createElement('a');
    link.href = url;
    link.download = `redis-batch-export-db${selectedDb.value}-${Date.now()}.json`;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
    
    ElMessage.success(`分批导出完成，共${Object.keys(allData).length}个键`);
    batchExportVisible.value = false;
  } catch (error) {
    console.error('分批导出失败:', error);
    ElMessage.error('分批导出失败: ' + error.message);
  }
};

// 执行自定义导出
const executeCustomExport = async () => {
  loading.value = true;
  try {
    const { exportCacheOptimized: exportAPI } = await import('@/api/redis');
    const response = await exportAPI(exportOptions.value.pattern, selectedDb.value, exportOptions.value.method);
    
    if (response.success) {
      if (response.exportMethod === 'json') {
        // JSON格式直接下载
        const dataStr = JSON.stringify(response.data, null, 2);
        const dataBlob = new Blob([dataStr], { type: 'application/json' });
        const url = URL.createObjectURL(dataBlob);
        const link = document.createElement('a');
        link.href = url;
        link.download = `redis-custom-export-db${selectedDb.value}-${Date.now()}.json`;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
        ElMessage.success(response.message);
        exportOptionsVisible.value = false;
      } else if (response.exportMethod === 'stream') {
        // 流式导出
        const { downloadCacheStream } = await import('@/api/redis');
        downloadCacheStream(exportOptions.value.pattern, selectedDb.value);
        ElMessage.success('开始流式下载...');
        exportOptionsVisible.value = false;
      } else if (response.exportMethod === 'batch') {
        // 分批导出
        exportOptionsVisible.value = false;
        showBatchExportDialog(response.exportInfo);
      }
    } else {
      ElMessage.error(response.message);
    }
  } catch (error) {
    console.error('自定义导出失败:', error);
    ElMessage.error('导出失败: ' + (error.message || '未知错误'));
  } finally {
    loading.value = false;
  }
};

// 显示导入对话框
const showImportDialog = () => {
  importDialogVisible.value = true;
  importData.value = '';
};

// 导入缓存
const importCache = async () => {
  if (!importData.value) {
    ElMessage.warning('请输入要导入的JSON数据');
    return;
  }
  
  loading.value = true;
  try {
    // 解析JSON数据
    const data = JSON.parse(importData.value);
    
    // 调用批量导入API
    const response = await redisStore.importCache(data, selectedDb.value);
    
    if (response.success) {
      const { successCount, skipCount, errorCount } = response.data || {};
      let message = `导入完成: 成功 ${successCount || 0} 个`;
      if (skipCount > 0) {
        message += `, 跳过 ${skipCount} 个`;
      }
      if (errorCount > 0) {
        message += `, 失败 ${errorCount} 个`;
      }
      
      ElMessage.success(message);
      importDialogVisible.value = false;
      
      // 刷新缓存键列表
      await loadCacheKeys();
    } else {
      ElMessage.error(response.message || '导入失败');
    }
  } catch (error) {
    console.error('导入缓存失败:', error);
    if (error.message.includes('JSON')) {
      ElMessage.error('JSON格式错误，请检查数据格式');
    } else {
      ElMessage.error('导入缓存失败: ' + (error.message || '未知错误'));
    }
  } finally {
    loading.value = false;
  }
};

// 确认清空缓存
const confirmClearCache = () => {
  ElMessageBox.confirm('确定要清空所有缓存吗？此操作不可恢复！', '警告', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    clearCache();
  }).catch(() => {
    // 取消操作
  });
};

// 清空缓存
const clearCache = async () => {
  loading.value = true;
  try {
    // 获取所有键
    const keys = await redisStore.getCacheKeys('*', selectedDb.value);
    let successCount = 0;
    
    // 删除所有键
    for (const key of keys) {
      try {
        // 确保key是字符串类型
        const keyStr = typeof key === 'object' ? JSON.stringify(key) : String(key);
        const result = await redisStore.removeCacheValue(keyStr, selectedDb.value);
        if (result) {
          successCount++;
          delete cacheValues.value[keyStr];
        }
      } catch (error) {
        console.error(`删除键 ${key} 失败:`, error);
      }
    }
    
    // 更新缓存键列表
    cacheKeys.value = [];
    ElMessage.success(`清空缓存成功: 删除了 ${successCount} 个键`);
  } catch (error) {
    console.error('清空缓存失败:', error);
    ElMessage.error('清空缓存失败: ' + (error.message || '未知错误'));
  } finally {
    loading.value = false;
  }
};

// 判断是否为集群模式
const isClusterMode = (redisData) => {
  if (!redisData || !redisData.mode) return false;
  return redisData.mode.includes('集群') || 
         redisData.mode.toLowerCase().includes('cluster');
};

// 获取显示版本信息 - 兼容集群和单机
const getDisplayVersion = (redisData) => {
  if (redisData.version && redisData.version !== '未知') {
    return redisData.version;
  }
  
  const isCluster = isClusterMode(redisData);
  if (isCluster) {
    return redisData.clusterVersion || '7.0+ 集群版';
  } else {
    return redisData.standaloneVersion || '7.0+ 单机版';
  }
};

// 获取显示内存信息 - 兼容集群和单机
const getDisplayMemory = (redisData) => {
  if (redisData.memory && redisData.memory !== '未知') {
    return redisData.memory;
  }
  
  const isCluster = isClusterMode(redisData);
  if (isCluster) {
    // 集群模式可能返回总内存或各节点内存
    return redisData.totalMemory || 
           redisData.clusterMemory || 
           redisData.usedMemoryTotal || 
           '集群总内存';
  } else {
    // 单机模式返回单个实例内存
    return redisData.usedMemory || 
           redisData.memoryUsage || 
           '128MB';
  }
};

onMounted(() => {
  // 初始化用户信息
  userStore.initUserInfo();
  
  // 检查是否有有效的token和用户信息
  const currentUser = userStore.getCurrentUsername();
  const token = localStorage.getItem('token');
  if (!token || currentUser === '未知用户') {
    console.warn('检测到无效会话，自动登出');
    userStore.logout().then(() => {
      router.push('/login');
    });
    return;
  }
  
  // 恢复Redis连接状态
  const wasConnected = localStorage.getItem('redis_connected') === 'true';
  if (wasConnected && redisStore.connected) {
    connected.value = true;
    fetchRedisInfo();
  } else {
    // 首次访问或连接已断开，默认连接DB0
    console.log(`首次访问Redis管理页面，默认连接DB${selectedDb.value}`);
    testConnection();
  }
});
</script>

<template>
  <div class="page-container" style="padding: 20px; width: 100%; max-width: 100%; box-sizing: border-box;">
    <div class="page-header">
      <h1>Redis 管理</h1>
      <div class="header-right">
        <el-tag v-if="connected" type="success" size="large">
          <el-icon><Check /></el-icon>
          已连接 DB{{ selectedDb }}
        </el-tag>
        <el-tag v-else type="danger" size="large">
          <el-icon><Close /></el-icon>
          未连接
        </el-tag>
      </div>
    </div>
    
    <el-tabs v-model="activeTab" type="border-card">
      <!-- 连接信息标签页 -->
      <el-tab-pane label="连接信息" name="connection">
        <el-card shadow="hover" class="connection-card">
          <template #header>
            <div class="card-header">
              <h3>Redis连接状态</h3>
              <div class="header-actions">
                <el-select v-model="selectedDb" @change="onDbChange" placeholder="选择数据库" style="width: 140px; margin-right: 10px;">
                  <el-option
                    v-for="item in dbOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                  </el-option>
                </el-select>
                <el-button type="primary" @click="testConnection" :loading="loading">测试连接</el-button>
              </div>
            </div>
          </template>
          <div v-loading="loading" class="connection-status">
            <el-alert
              :title="connected ? 'Redis连接正常' : 'Redis未连接'"
              :type="connected ? 'success' : 'error'"
              :description="connected ? '可以正常进行缓存操作' : '请检查Redis服务是否启动'"
              show-icon
              :closable="false"
            />
            
            <div v-if="connected && redisInfo" class="redis-info">
              <h4>Redis服务信息</h4>
              <el-row :gutter="16">
                <el-col :span="6">
                  <el-card class="info-card memory-card">
                    <div class="info-content">
                      <div class="info-icon">
                        <el-icon><Cpu /></el-icon>
                      </div>
                      <div class="info-text">
                        <div class="info-title">内存使用</div>
                        <div class="info-value">{{ getDisplayMemory(redisInfo) }}</div>
                      </div>
                    </div>
                  </el-card>
                </el-col>
                <el-col :span="6">
                  <el-card class="info-card total-memory-card">
                    <div class="info-content">
                      <div class="info-icon">
                        <el-icon><Monitor /></el-icon>
                      </div>
                      <div class="info-text">
                        <div class="info-title">总内存</div>
                        <div class="info-value">{{ redisInfo.totalMemory || redisInfo.maxMemory || '2GB' }}</div>
                      </div>
                    </div>
                  </el-card>
                </el-col>
                <el-col :span="6">
                  <el-card class="info-card connections-card">
                    <div class="info-content">
                      <div class="info-icon">
                        <el-icon><Connection /></el-icon>
                      </div>
                      <div class="info-text">
                        <div class="info-title">连接数</div>
                        <div class="info-value">{{ redisInfo.connections || redisInfo.connectedClients || '0' }}</div>
                      </div>
                    </div>
                  </el-card>
                </el-col>
                <el-col :span="6">
                  <el-card class="info-card status-card">
                    <div class="info-content">
                      <div class="info-icon">
                        <el-icon><Check /></el-icon>
                      </div>
                      <div class="info-text">
                        <div class="info-title">服务状态</div>
                        <div class="info-value status-normal">{{ redisInfo.clusterState || '正常' }}</div>
                      </div>
                    </div>
                  </el-card>
                </el-col>
              </el-row>
              <el-row :gutter="16" style="margin-top: 16px;">
                <el-col :span="8">
                  <el-card class="info-card version-card">
                    <div class="info-content">
                      <div class="info-icon">
                        <el-icon><InfoFilled /></el-icon>
                      </div>
                      <div class="info-text">
                        <div class="info-title">版本</div>
                        <div class="info-value">{{ getDisplayVersion(redisInfo) }}</div>
                      </div>
                    </div>
                  </el-card>
                </el-col>
                <el-col :span="8">
                  <el-card class="info-card mode-card">
                    <div class="info-content">
                      <div class="info-icon">
                        <el-icon><Setting /></el-icon>
                      </div>
                      <div class="info-text">
                        <div class="info-title">模式</div>
                        <div class="info-value">
                          <el-tag :type="isClusterMode(redisInfo) ? 'warning' : 'success'">
                            {{ redisInfo.mode || 'standalone' }}
                          </el-tag>
                        </div>
                      </div>
                    </div>
                  </el-card>
                </el-col>
                <el-col :span="8">
                  <el-card class="info-card nodes-card">
                    <div class="info-content">
                      <div class="info-icon">
                        <el-icon><Coordinate /></el-icon>
                      </div>
                      <div class="info-text">
                        <div class="info-title">节点数</div>
                        <div class="info-value">{{ redisInfo.clusterNodes || redisInfo.nodeCount || '1' }}</div>
                      </div>
                    </div>
                  </el-card>
                </el-col>
              </el-row>
            </div>
          </div>
        </el-card>
      </el-tab-pane>
      
      <!-- 缓存管理标签页 -->
      <el-tab-pane label="缓存管理" name="cache">
        <el-row :gutter="20">
          <!-- 左侧：缓存操作区域 -->
          <el-col :span="12">
            <el-card shadow="hover" class="cache-card">
              <template #header>
                <div class="card-header">
                  <h3>缓存操作</h3>
                </div>
              </template>
              <div v-loading="loading" class="cache-form">
                <el-form :model="cacheForm" label-width="80px">
                  <el-form-item label="缓存键">
                    <el-input v-model="cacheForm.key" placeholder="请输入缓存键" />
                  </el-form-item>
                  <el-form-item label="数据类型">
                    <el-select v-model="cacheForm.type" @change="onTypeChange" placeholder="选择数据类型" style="width: 100%;">
                      <el-option
                        v-for="item in dataTypeOptions"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value">
                      </el-option>
                    </el-select>
                  </el-form-item>
                  <!-- String类型输入 -->
                  <el-form-item v-if="cacheForm.type === 'string'" label="缓存值">
                    <el-input 
                      v-model="cacheForm.value" 
                      type="textarea" 
                      :rows="2"
                      placeholder="请输入字符串值" />
                  </el-form-item>

                  <!-- List类型输入 -->
                  <el-form-item v-if="cacheForm.type === 'list'" label="列表项">
                    <el-input 
                      v-model="cacheForm.value" 
                      type="textarea" 
                      :rows="4"
                      placeholder="每行一个列表项" />
                    <div class="type-hint">
                      <el-text size="small" type="info">提示：每行输入一个列表项，将按顺序添加到列表中</el-text>
                    </div>
                  </el-form-item>

                  <!-- Set类型输入 -->
                  <el-form-item v-if="cacheForm.type === 'set'" label="集合成员">
                    <el-input 
                      v-model="cacheForm.value" 
                      type="textarea" 
                      :rows="4"
                      placeholder="每行一个集合成员" />
                    <div class="type-hint">
                      <el-text size="small" type="info">提示：每行输入一个集合成员，重复项会自动去重</el-text>
                    </div>
                  </el-form-item>

                  <!-- Hash类型输入 -->
                  <template v-if="cacheForm.type === 'hash'">
                    <el-form-item label="字段名">
                      <el-input v-model="cacheForm.hashField" placeholder="请输入字段名" />
                    </el-form-item>
                    <el-form-item label="字段值">
                      <el-input v-model="cacheForm.hashValue" placeholder="请输入字段值" />
                    </el-form-item>
                    <div class="type-hint">
                      <el-text size="small" type="info">提示：Hash类型存储字段-值对，一次设置一个字段</el-text>
                    </div>
                  </template>

                  <!-- ZSet类型输入 -->
                  <template v-if="cacheForm.type === 'zset'">
                    <el-form-item label="成员">
                      <el-input v-model="cacheForm.zsetMember" placeholder="请输入成员名称" />
                    </el-form-item>
                    <el-form-item label="分数">
                      <el-input-number 
                        v-model="cacheForm.zsetScore" 
                        :precision="2"
                        placeholder="请输入分数" 
                        style="width: 100%;" />
                    </el-form-item>
                    <div class="type-hint">
                      <el-text size="small" type="info">提示：有序集合根据分数排序，分数可以是小数</el-text>
                    </div>
                  </template>
                  <el-form-item label="过期时间">
                    <el-input-number 
                      v-model="cacheForm.expire" 
                      :min="0" 
                      :step="1" 
                      placeholder="秒数，0表示永不过期" 
                      style="width: 100%;" />
                  </el-form-item>
                  <el-form-item>
                    <el-button type="primary" @click="setCache" :disabled="!connected">设置缓存</el-button>
                    <el-button type="success" @click="getCache" :disabled="!connected">获取缓存</el-button>
                    <el-button type="danger" @click="deleteCache" :disabled="!connected">删除缓存</el-button>
                  </el-form-item>
                </el-form>
              </div>
            </el-card>
          </el-col>
          
          <!-- 右侧：缓存键列表 -->
          <el-col :span="12">
            <el-card shadow="hover">
              <template #header>
                <div class="card-header">
                  <h3>缓存键列表 ({{ filteredCacheKeys.length }})</h3>
                  <div class="header-actions">
                    <el-input
                      v-model="searchKey"
                      placeholder="输入键名模式(如:user:*)"
                      prefix-icon="el-icon-search"
                      style="width: 200px; margin-right: 8px;"
                      size="small"
                      clearable
                      @keyup.enter="loadCacheKeys(searchKey)"
                    />
                    <el-button 
                      type="primary" 
                      size="small" 
                      @click="loadCacheKeys(searchKey)"
                      :disabled="!connected || (!searchKey && isProduction)"
                    >
                      搜索
                    </el-button>
                    <el-button 
                      type="success" 
                      size="small" 
                      @click="exportCacheData"
                      :disabled="!connected || cacheKeys.length === 0"
                      style="margin-left: 8px;"
                    >
                      导出
                    </el-button>
                    <el-select v-model="selectedKeyType" placeholder="类型" style="width: 80px; margin-left: 8px;" size="small">
                      <el-option label="全部" value="all" />
                      <el-option label="字符" value="string" />
                      <el-option label="数字" value="number" />
                      <el-option label="JSON" value="json" />
                    </el-select>
                  </div>
                </div>
              </template>
              <div class="cache-keys-container" style="max-height: 350px; overflow-y: auto;">
                <el-empty v-if="filteredCacheKeys.length === 0" description="暂无缓存键" />
                <div v-else class="cache-keys-list">
                  <div
                    v-for="key in filteredCacheKeys"
                    :key="key"
                    class="cache-key-item"
                    @click="selectCacheKey(key)">
                    <div class="key-header">
                      <span class="key-name">{{ key }}</span>
                      <el-tag
                        :type="getValueType(key, cacheValues[key]) === 'list' ? 'success' : 
                               getValueType(key, cacheValues[key]) === 'set' ? 'warning' : 
                               getValueType(key, cacheValues[key]) === 'hash' ? 'danger' :
                               getValueType(key, cacheValues[key]) === 'zset' ? 'info' : 'primary'"
                        size="small">
                        {{ getValueType(key, cacheValues[key]).toUpperCase() }}
                      </el-tag>
                    </div>
                    <div class="key-value" v-if="cacheValues[key] !== undefined">
                      <pre v-if="getValueType(key, cacheValues[key]) === 'list'" class="list-preview">{{ formatValue(key, cacheValues[key]) }}</pre>
                      <pre v-else-if="getValueType(key, cacheValues[key]) === 'set'" class="set-preview">{{ formatValue(key, cacheValues[key]) }}</pre>
                      <pre v-else-if="getValueType(key, cacheValues[key]) === 'hash'" class="hash-preview">{{ formatValue(key, cacheValues[key]) }}</pre>
                      <pre v-else-if="getValueType(key, cacheValues[key]) === 'zset'" class="zset-preview">{{ formatValue(key, cacheValues[key]) }}</pre>
                      <span v-else class="string-preview">{{ String(cacheValues[key]).substring(0, 50) }}{{ String(cacheValues[key]).length > 50 ? '...' : '' }}</span>
                    </div>
                    <div class="key-actions">
                      <el-button type="text" size="small" @click.stop="getCacheByKey(key)">查看</el-button>
                      <el-button type="text" size="small" @click.stop="deleteCacheByKey(key)" class="delete-btn">删除</el-button>
                    </div>
                  </div>
                </div>
              </div>
              
              <!-- 分页控件 -->
              <div v-if="totalKeys > 0" class="pagination-container" style="margin-top: 16px; text-align: center;">
                <el-pagination
                  v-model:current-page="currentPage"
                  v-model:page-size="pageSize"
                  :page-sizes="[20, 50, 100]"
                  :total="totalKeys"
                  layout="total, sizes, prev, pager, next, jumper"
                  @size-change="handleSizeChange"
                  @current-change="handleCurrentChange"
                  small
                />
              </div>
            </el-card>
          </el-col>
        </el-row>
      </el-tab-pane>
      
      <!-- 批量操作标签页 -->
      <el-tab-pane label="批量操作" name="batch">
        <el-card shadow="hover">
          <template #header>
            <div class="card-header">
              <h3>批量操作</h3>
            </div>
          </template>
          <div class="batch-operations">
            <el-row :gutter="20">
              <el-col :span="8">
                <el-card shadow="hover" class="batch-card">
                  <template #header>
                    <div class="card-header">
                      <h4>导出缓存</h4>
                    </div>
                  </template>
                  <div class="batch-content">
                    <p>智能导出缓存数据，自动选择最优方案</p>
                    <el-row :gutter="10">
                      <el-col :span="12">
                        <el-button type="primary" @click="exportCacheOptimized" :loading="loading" :disabled="!connected" style="width: 100%">
                          <el-icon><Download /></el-icon> 智能导出
                        </el-button>
                      </el-col>
                      <el-col :span="12">
                        <el-button type="success" @click="exportCacheStream" :loading="loading" :disabled="!connected" style="width: 100%">
                          <el-icon><Download /></el-icon> 流式下载
                        </el-button>
                      </el-col>
                    </el-row>
                    <el-row :gutter="10" style="margin-top: 8px;">
                      <el-col :span="24">
                        <el-button type="info" @click="showExportOptions" :disabled="!connected" style="width: 100%" size="small">
                          <el-icon><Setting /></el-icon> 高级导出选项
                        </el-button>
                      </el-col>
                    </el-row>
                  </div>
                </el-card>
              </el-col>
              <el-col :span="8">
                <el-card shadow="hover" class="batch-card">
                  <template #header>
                    <div class="card-header">
                      <h4>导入缓存</h4>
                    </div>
                  </template>
                  <div class="batch-content">
                    <p>从JSON文件导入缓存键值对</p>
                    <el-button type="success" @click="showImportDialog" :disabled="!connected">
                      <el-icon><Upload /></el-icon> 导入缓存
                    </el-button>
                  </div>
                </el-card>
              </el-col>
              <el-col :span="8">
                <el-card shadow="hover" class="batch-card">
                  <template #header>
                    <div class="card-header">
                      <h4>清空缓存</h4>
                    </div>
                  </template>
                  <div class="batch-content">
                    <p>清空当前数据库中的所有缓存</p>
                    <el-tooltip
                      content="清空缓存功能已被永久禁用，这是一个危险操作"
                      placement="top"
                    >
                      <el-button type="danger" disabled>
                        <el-icon><Delete /></el-icon> 清空缓存(已禁用)
                      </el-button>
                    </el-tooltip>
                  </div>
                </el-card>
              </el-col>
            </el-row>
          </div>
        </el-card>
      </el-tab-pane>
    </el-tabs>
    
    <!-- 导入对话框 -->
    <el-dialog v-model="importDialogVisible" title="导入缓存" width="50%">
      <el-form>
        <el-form-item label="JSON数据">
          <el-input 
            v-model="importData" 
            type="textarea" 
            :rows="10"
            placeholder="请输入JSON格式的键值对数据" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="importDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="importCache" :loading="loading">导入</el-button>
      </template>
    </el-dialog>

    <!-- 高级导出选项对话框 -->
    <el-dialog v-model="exportOptionsVisible" title="高级导出选项" width="40%">
      <el-form :model="exportOptions" label-width="100px">
        <el-form-item label="键名模式">
          <el-input v-model="exportOptions.pattern" placeholder="支持通配符，如 user:*" />
          <div class="form-hint">支持Redis通配符：* ? [] 等</div>
        </el-form-item>
        <el-form-item label="导出方式">
          <el-select v-model="exportOptions.method" style="width: 100%">
            <el-option label="自动选择（推荐）" value="auto" />
            <el-option label="JSON格式" value="json" />
            <el-option label="流式下载" value="stream" />
            <el-option label="分批导出" value="batch" />
          </el-select>
        </el-form-item>
        <el-form-item label="批次大小" v-if="exportOptions.method === 'batch'">
          <el-input-number v-model="exportOptions.batchSize" :min="100" :max="10000" />
          <div class="form-hint">每批导出的键数量，建议1000-5000</div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="exportOptionsVisible = false">取消</el-button>
        <el-button type="primary" @click="executeCustomExport" :loading="loading">开始导出</el-button>
      </template>
    </el-dialog>

    <!-- 分批导出进度对话框 -->
    <el-dialog v-model="batchExportVisible" title="分批导出进度" width="50%" :close-on-click-modal="false">
      <div class="batch-export-progress">
        <el-descriptions title="导出信息" :column="2" border>
          <el-descriptions-item label="总键数">{{ batchExportInfo.totalKeys }}</el-descriptions-item>
          <el-descriptions-item label="批次大小">{{ batchExportInfo.batchSize }}</el-descriptions-item>
          <el-descriptions-item label="总批次">{{ batchExportInfo.totalBatches }}</el-descriptions-item>
          <el-descriptions-item label="当前批次">{{ currentBatch }} / {{ batchExportInfo.totalBatches }}</el-descriptions-item>
        </el-descriptions>
        
        <div style="margin: 20px 0;">
          <div style="margin-bottom: 10px;">导出进度：{{ batchExportProgress }}%</div>
          <el-progress :percentage="batchExportProgress" :status="batchExportProgress === 100 ? 'success' : null" />
        </div>
      </div>
      <template #footer>
        <el-button @click="batchExportVisible = false" :disabled="batchExportProgress > 0 && batchExportProgress < 100">
          {{ batchExportProgress === 100 ? '关闭' : '取消' }}
        </el-button>
        <el-button type="primary" @click="executeBatchExport" :loading="batchExportProgress > 0 && batchExportProgress < 100" v-if="batchExportProgress === 0">
          开始分批导出
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped>
/* 统一页面容器样式 - Author: Logan.Li */
.page-container {
  padding: 20px;
  min-height: calc(100vh - 60px);
  background-color: #f5f5f5;
}

/* 数据类型提示样式 */
.type-hint {
  margin-top: 5px;
  padding: 5px 10px;
  background-color: #f0f9ff;
  border-left: 3px solid #409EFF;
  border-radius: 4px;
}

/* 不同数据类型的语法高亮样式 */
.list-preview {
  background-color: #f0f9f0;
  border-left: 3px solid #67C23A;
  padding: 8px;
  margin: 0;
  font-size: 12px;
  line-height: 1.4;
}

/* 表单提示样式 */
.form-hint {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
  line-height: 1.4;
}

/* 分批导出进度样式 */
.batch-export-progress {
  padding: 10px 0;
}

.batch-export-progress .el-descriptions {
  margin-bottom: 20px;
  white-space: pre-wrap;
  border-radius: 4px;
  min-height: 20px;
  max-height: 200px;
  overflow-y: auto;
  word-break: break-all;
}

.set-preview {
  background-color: #fdf6ec;
  border-left: 3px solid #E6A23C;
  padding: 8px;
  margin: 0;
  font-size: 12px;
  line-height: 1.4;
  white-space: pre-wrap;
  border-radius: 4px;
  min-height: 20px;
  max-height: 200px;
  overflow-y: auto;
  word-break: break-all;
}

.hash-preview {
  background-color: #fef0f0;
  border-left: 3px solid #F56C6C;
  padding: 8px;
  margin: 0;
  font-size: 12px;
  line-height: 1.4;
  white-space: pre-wrap;
  border-radius: 4px;
  min-height: 20px;
  max-height: 200px;
  overflow-y: auto;
  word-break: break-all;
}

.zset-preview {
  background-color: #f4f4f5;
  border-left: 3px solid #909399;
  padding: 8px;
  margin: 0;
  font-size: 12px;
  line-height: 1.4;
  white-space: pre-wrap;
  border-radius: 4px;
  min-height: 20px;
  max-height: 200px;
  overflow-y: auto;
  word-break: break-all;
}

.string-preview {
  color: #606266;
  font-size: 12px;
}

/* 主内容区域 */
.content {
    flex: 1;
    overflow: auto;
    padding: 0;
    background-color: #f0f2f5;
}

/* 统一页面头部样式 */
.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 20px;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.page-header h1 {
  margin: 0;
  color: #333;
  font-size: 24px;
  font-weight: 600;
}

.header-right {
  display: flex;
  align-items: center;
}

/* 统一卡片样式 */
.el-card {
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  margin-bottom: 20px;
}
</style>
